/*
    网络消息的具象描述
*/

#pragma once

#include "abstract.hpp"
#include "detail.hpp"
#include "fields.hpp"
#include <vector>

namespace myrpc
{
    typedef std::pair<std::string, int> Address;

    //json封装
    class JsonMessage : public BaseMessage
    {
    public:
        typedef std::shared_ptr<JsonMessage> ptr;

        virtual std::string serialize() override { return JSON::serialize(_body); }
        virtual void unserialize(const std::string& msg) override { _body = JSON::unserialize(msg); }
        virtual bool check() = 0;
    protected:
        Json::Value _body; // 有效载荷
    };

    //json请求
    class JsonRequest : public JsonMessage
    {
    public:
        typedef std::shared_ptr<JsonRequest> ptr;
    };

    //json应答
    class JsonResponse : public JsonMessage
    {
    public:
        typedef std::shared_ptr<JsonResponse> ptr;
        virtual bool check() override
        {
            //这里只判断响应状态码是否存在且合法
            if(_body[KEY_RCODE].isNull())
            {
                ELOG("没有相应状态码");
                return false;
            }
            if(!_body[KEY_RCODE].isIntegral())
            {
                ELOG("相应状态码类型错误");
                return false;
            }
            return true;
        }

        RCode rcode() { return (RCode)_body[KEY_RCODE].asInt(); } 
        void setRcode(RCode rcode) { _body[KEY_RCODE] = (int)rcode; }
    };

    //RPC请求
    class RpcRequest : public JsonRequest
    {
    public:
        typedef std::shared_ptr<RpcRequest> ptr;
        virtual bool check() override
        {
            if(_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString())
            {
                ELOG("RPC请求中无方法名称或方法名称不合法");
                return false;
            }
            if(_body[KEY_PARAMS].isNull() || !_body[KEY_PARAMS].isObject())
            {
                ELOG("RPC请求中无方法参数或方法参数不合法");
                return false;
            }
            return true;
        }
        std::string method() { return _body[KEY_METHOD].asString(); }
        void setMethod(const std::string& method) { _body[KEY_METHOD] = method; }

        Json::Value params() { return _body[KEY_PARAMS]; }
        void setParams(const Json::Value& params) { _body[KEY_METHOD] = params; }
    };

    //主题请求
    class TopicRequest : public JsonRequest
    {
    public:
        typedef std::shared_ptr<TopicRequest> ptr;
        virtual bool check() override
        {
            if(_body[KEY_TOPIC_KEY].isNull() || !_body[KEY_TOPIC_KEY].isString())
            {
                ELOG("主题请求中无主题名称或主题名称不合法");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("主题请求中无操作类型或操作类型不合法");
                return false;
            }
            if(_body[KEY_OPTYPE].asInt() == (int)TopicOptype::TOPIC_PUBLISH && 
                (_body[KEY_TOPIC_MSG].isNull() || !_body[KEY_TOPIC_MSG].isString()))
            {
                ELOG("主题发布请求中无消息字段或消息字段不合法");
                return false;
            }
            return true;
        }

        std::string topicKey() { return _body[KEY_TOPIC_KEY].asString(); }
        void setTopicKey(const std::string& topickey) { _body[KEY_TOPIC_KEY] = topickey; }

        TopicOptype topicOptype() { return (TopicOptype)_body[KEY_OPTYPE].asInt(); }
        void setTopicOptype(TopicOptype type) { _body[KEY_OPTYPE] = (int)type; }

        std::string topicMsg() { return _body[KEY_TOPIC_MSG].asString(); }
        void setTopicMsg(const std::string& msg) { _body[KEY_TOPIC_MSG] = msg; }
    };

    //服务请求
    class ServiceRequest : public JsonRequest
    {
    public:
        typedef std::shared_ptr<ServiceRequest> ptr;
        virtual bool check() override
        {
            if(_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString())
            {
                ELOG("服务请求中无服务名称或服务名称不合法");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("服务请求中无操作类型或操作类型不合法");
                return false;
            }
            if(_body[KEY_OPTYPE].asInt() != (int)ServiceOptype::SERVICE_DISCOVERY &&
                (_body[KEY_HOST].isNull() || !_body[KEY_HOST].isObject() ||
                _body[KEY_HOST][KEY_HOST_IP].isNull() || !_body[KEY_HOST][KEY_HOST_IP].isString() || 
                _body[KEY_HOST][KEY_HOST_PORT].isNull() || !_body[KEY_HOST][KEY_HOST_PORT].isIntegral()))
            {
                ELOG("服务请求中地址信息错误");
                return false;
            }
            return true;
        }

        std::string method() { return _body[KEY_METHOD].asString(); }
        void setMethod(const std::string& method) { _body[KEY_METHOD] = method; }

        ServiceOptype serviceOptype() { return (ServiceOptype)_body[KEY_OPTYPE].asInt(); }
        void setServiceOptype(ServiceOptype type) { _body[KEY_OPTYPE] = (int)type; }

        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }

        void setHost(const Address addr)
        {
            _body[KEY_HOST][KEY_HOST_IP] = addr.first;
            _body[KEY_HOST][KEY_HOST_PORT] = addr.second;
        }
    };

    //RPC应答
    class RpcResponse : public JsonResponse
    {
    public:
        typedef std::shared_ptr<RpcResponse> ptr;
        virtual bool check() override
        {
            if(_body[KEY_RCODE].isNull() || !_body[KEY_RCODE].isIntegral())
            {
                ELOG("没有响应状态码或响应状态码类型错误");
                return false;
            }
            if(_body[KEY_RESULT].isNull())
            {
                ELOG("没有RPC返回结果");
                return false;
            }
            return true;
        }        

        Json::Value result() { return _body[KEY_RESULT]; }
        void setResult(const Json::Value& result) { _body[KEY_RESULT] = result; }
    };

    //主题应答
    class TopicResponse : public JsonResponse
    {
    public:
        typedef std::shared_ptr<TopicResponse> ptr;
    };

    //服务应答
    class ServiceResponse : public JsonResponse
    {
    public:
        typedef std::shared_ptr<ServiceResponse> ptr;
        virtual bool check() override
        {
            if(_body[KEY_RCODE].isNull() || !_body[KEY_RCODE].isIntegral())
            {
                ELOG("没有响应状态码或响应状态码类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].isNull() || !_body[KEY_OPTYPE].isIntegral())
            {
                ELOG("没有响应或响应类型错误");
                return false;
            }
            if(_body[KEY_OPTYPE].asInt() == (int)ServiceOptype::SERVICE_DISCOVERY && 
                (_body[KEY_METHOD].isNull() || !_body[KEY_METHOD].isString() || 
                _body[KEY_HOST].isNull() || !_body[KEY_HOST].isArray()))
            {
                ELOG("服务发现应答中，响应信息字段错误");
                return false;
            }
            return true;
        }

        std::string method() { return _body[KEY_METHOD].asString(); }
        void setMethod(const std::string& method) { _body[KEY_METHOD] = method; }

        std::vector<Address> hosts()
        {
            std::vector<Address> ret;
            int sz = _body[KEY_HOST].size();
            for(int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                ret.push_back(addr);
            }
            return ret;
        }
        void setHosts(const std::vector<Address>& addrs)
        {
            for(auto& addr : addrs)
            {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
    };

    //消息对象的生产工厂(简单工厂)
    class MessageFactory
    {
    public:
        static BaseMessage::ptr create(MType type)
        {
            switch(type)
            {
                case MType::REQ_RPC: return std::make_shared<RpcRequest>();
                case MType::REQ_TOPIC: return std::make_shared<TopicRequest>();
                case MType::REQ_SERVICE: return std::make_shared<ServiceRequest>();
                case MType::RSP_RPC: return std::make_shared<RpcResponse>();
                case MType::RSP_TOPIC: return std::make_shared<TopicResponse>();
                case MType::RSP_SERVICE: return std::make_shared<ServiceResponse>();
                default: return nullptr;
            }
        }

        template<class T, class ...Args>
        static std::shared_ptr<T> create(Args&& ...args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };
}